package cn.jbolt.ai.core.func;

import cn.hutool.core.util.StrUtil;
import cn.jbolt.ai.core.chain.ChainContext;
import cn.jbolt.ai.resource.function.entity.AiFunctionParam;
import cn.jbolt.ai.resource.function.entity.AiFunctionResource;
import cn.jbolt.ai.resource.function.service.AiFunctionResourceService;
import cn.jbolt.util.DateUtil;
import cn.jbolt.util.ObjectUtil;
import cn.jbolt.util.Result;
import cn.jbolt.util.SpringContextUtil;
import com.jboltai.capability.functioncall.FuncCallResult;
import com.jboltai.event.ai.aifunccall.AIFuncCallEvent;
import com.jboltai.util.other.ParamType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Time;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 本地方法调用
 */
@Component
public class NativeFunctionCall {


    // 用于缓存Method对象，避免重复反射获取
    private static final Map<String, Method> methodCache = new ConcurrentHashMap<>();


    private static AiFunctionResourceService functionResourceService;


    // 构造函数注入
    @Autowired
    public NativeFunctionCall(AiFunctionResourceService functionResourceService) {
        this.functionResourceService = functionResourceService;

    }


    /**
     * 调用本地方法
     *
     * @param result  方法调用结果
     * @param event   function call 事件
     * @param session 会话
     * @return
     */
    public static Result<FunctionCallResult> call(FuncCallResult result, AIFuncCallEvent event, WebSocketSession session) {
        return call(result, event, session, null);
    }
    /**
     * 调用本地方法
     *
     * @param result  方法调用结果
     * @param event   function call 事件
     * @param chainContext 事件链上下文
     * @return
     */
    public static Result<FunctionCallResult> call(FuncCallResult result, AIFuncCallEvent event, ChainContext chainContext) {
        return call(result, event, chainContext.getSocketSession(), chainContext);
    }

    /**
     * 调用本地方法
     *
     * @param result  方法调用结果
     * @param event   function call 事件
     * @param session 会话
     * @param chainContext 事件链上下文
     * @return
     */
    public static Result<FunctionCallResult> call(FuncCallResult result, AIFuncCallEvent event, WebSocketSession session, ChainContext chainContext) {
        try {
            // 1. 获取AIFunctionResource对象
            Result<AiFunctionResource> functionResult = functionResourceService.getFunctionById(Long.parseLong(result.getFunctionId()));
            if (!functionResult.isSuccess() || functionResult.getData() == null) {
                return Result.error("资源中心未找到 Function资源: " + result.getFunctionId());
            }
            AiFunctionResource functionResource = functionResult.getData();

            if (!functionResource.getEnable()) {
                return Result.error("Function资源已禁用: " + result.getFunctionId());
            }

            // 2. 获取方法对象(从缓存中获取)
            String methodKey = functionResource.getServiceClass() + "#" + functionResource.getServiceMethod();
            Method method = methodCache.computeIfAbsent(methodKey, k -> {
                try {
                    Class<?> serviceClass = Class.forName(functionResource.getServiceClass());
                    Method declaredMethod = serviceClass.getDeclaredMethod(functionResource.getServiceMethod());
                    return declaredMethod;
                } catch (Exception e) {
                    throw new RuntimeException("获取Function资源失败: " + methodKey, e);
                }
            });

            // 获取service实例
            Class<?> serviceClass = method.getDeclaringClass();
            Object serviceInstance = SpringContextUtil.getApplicationContext().getBean(serviceClass);

            // 3. 获取方法参数列表
            Parameter[] parameters = method.getParameters();
            Object[] args = new Object[parameters.length];
            Map<String, Object> paramValues = result.getParameters();

            // 4. 转换参数值
            for (int i = 0; i < parameters.length; i++) {
                Parameter param = parameters[i];
                if (param.getType() == AIFuncCallEvent.class) {
                    args[i] = event;
                } else if (WebSocketSession.class.isAssignableFrom(param.getType())) {
                    args[i] = session;
                } else if (param.getType() == ChainContext.class) {
                    args[i] = chainContext;
                } else {
                    Object value = paramValues.get(param.getName());
                    args[i] = ObjectUtil.convert(value == null ? null : value.toString(), param.getParameterizedType());
                }
            }

            // 5. 通过反射调用方法
            Object returnValue = method.invoke(serviceInstance, args);

            // 6. 包装返回结果
            if (returnValue instanceof Result) {
                returnValue = ((Result<?>) returnValue).getData();
            }
            return Result.success(new FunctionCallResult(returnValue, functionResource));


        } catch (Exception e) {
            return Result.error("Function 执行失败: " + e.getMessage());
        }
    }

    // 存储方法到缓存中
    public static void cacheMethod(String key, Method method) {
        if (method != null) {
            methodCache.put(key, method);
        }
    }
    //缓存中移除
    public static void removeMethod(String key) {
        methodCache.remove(key);
    }


    private static Class<?>[] getFunctionParameterTypes( List<AiFunctionParam> params) throws ClassNotFoundException {
        List<Class<?>> typeList = new ArrayList<>();
        if (params != null && params.size() > 0) {
            for (AiFunctionParam param : params) {
                typeList.add(Class.forName(param.getType()));
            }
        }
        return typeList.toArray(new Class<?>[0]);
    }

    /**
     * 获取method方法
     * @param fullPathClassName
     * @param methodName
     * @param params
     * @return
     */
    public  static Method getMethod(String fullPathClassName, String methodName, List<AiFunctionParam> params) {
        try {
            // 获取Controller类对象
            Class<?> controllerClass = Class.forName(fullPathClassName);
            // 解析参数类型数组，用于获取对应的方法对象
            Class<?>[] parameterTypes = getFunctionParameterTypes(params);
            // 获取要调用的方法对象
            Method method = controllerClass.getMethod(methodName, parameterTypes);
            // 调用方法
            return method;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }

    }
}
